# -*- coding: utf-8 -*-
"""
省份地理边界工具模块

此模块提供用于提取和处理中国省份地理边界数据的函数和类。
主要功能包括：
- 从shapefile中提取省份边界数据
- 计算省份的经纬度范围
- 生成省份边界的可视化地图
"""

import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt
import os
from typing import List, Dict, Any, Optional, Tuple


def read_province_shapefile(shp_path: str, encoding: str = 'utf-8') -> gpd.GeoDataFrame:
    """
    读取省份shapefile文件并确保使用地理坐标系统(WGS84)
    
    参数:
        shp_path: shapefile文件路径
        encoding: 文件编码，默认为utf-8
        
    返回:
        包含省份数据的GeoDataFrame对象
    """
    try:
        # 读取shapefile文件
        gdf = gpd.read_file(shp_path, encoding=encoding)
        print(f"成功读取shapefile文件，共有{len(gdf)}个省份")
        
        # 确保坐标系统是地理坐标系统(WGS84)
        if gdf.crs and not gdf.crs.is_geographic:
            print(f"原始坐标系统: {gdf.crs}")
            gdf = gdf.to_crs("EPSG:4326")  # 转换为WGS84地理坐标系
            print(f"已转换为WGS84坐标系统: {gdf.crs}")
            
        return gdf
    except Exception as e:
        print(f"读取shapefile文件时出错: {e}")
        raise


def filter_provinces(gdf: gpd.GeoDataFrame, target_provinces: List[str], 
                     name_field: str = 'NAME') -> gpd.GeoDataFrame:
    """
    从GeoDataFrame中筛选指定的省份
    
    参数:
        gdf: 包含所有省份数据的GeoDataFrame
        target_provinces: 目标省份名称列表
        name_field: 省份名称字段，默认为'NAME'
        
    返回:
        筛选后的GeoDataFrame
    """
    filtered_gdf = gdf[gdf[name_field].isin(target_provinces)]
    print(f"找到{len(filtered_gdf)}个目标省份")
    
    if len(filtered_gdf) < len(target_provinces):
        found_provinces = filtered_gdf[name_field].tolist()
        missing_provinces = [p for p in target_provinces if p not in found_provinces]
        print(f"未找到以下省份: {missing_provinces}")
        
    return filtered_gdf


def extract_province_bounds(filtered_gdf: gpd.GeoDataFrame, 
                           name_field: str = 'NAME', 
                           fullname_field: str = '省全名') -> pd.DataFrame:
    """
    提取省份的经纬度边界范围
    
    参数:
        filtered_gdf: 筛选后的省份GeoDataFrame
        name_field: 省份名称字段，默认为'NAME'
        fullname_field: 省份全称字段，默认为'省全名'
        
    返回:
        包含省份边界数据的DataFrame
    """
    results = []
    
    # 提取每个省份的边界范围
    for idx, row in filtered_gdf.iterrows():
        province_name = row[name_field]
        bounds = row['geometry'].bounds  # 返回(minx, miny, maxx, maxy)
        
        results.append({
            '省份': province_name,
            '全称': row[fullname_field] if fullname_field in row else province_name,
            '最小经度': bounds[0],
            '最小纬度': bounds[1],
            '最大经度': bounds[2],
            '最大纬度': bounds[3],
            '经度范围': f"{bounds[0]:.6f} - {bounds[2]:.6f}",
            '纬度范围': f"{bounds[1]:.6f} - {bounds[3]:.6f}"
        })
    
    return pd.DataFrame(results)


def create_province_map(gdf: gpd.GeoDataFrame, filtered_gdf: gpd.GeoDataFrame, 
                       output_path: str, name_field: str = 'NAME', 
                       figsize: Tuple[int, int] = (15, 10), dpi: int = 300) -> str:
    """
    创建省份边界地图并保存为图像文件
    
    参数:
        gdf: 包含所有省份数据的GeoDataFrame
        filtered_gdf: 筛选后的目标省份GeoDataFrame
        output_path: 输出图像文件路径
        name_field: 省份名称字段，默认为'NAME'
        figsize: 图像大小，默认为(15, 10)
        dpi: 图像分辨率，默认为300
        
    返回:
        保存的图像文件路径
    """
    print("正在生成可视化地图...")
    
    # 设置图形大小
    plt.figure(figsize=figsize)
    
    # 绘制所有省份作为背景（灰色）
    gdf.plot(ax=plt.gca(), color='lightgrey', edgecolor='grey', linewidth=0.5)
    
    # 绘制目标省份（彩色）
    filtered_gdf.plot(ax=plt.gca(), column=name_field, cmap='tab20', 
                     edgecolor='black', linewidth=0.8, legend=True)
    
    # 添加省份标签
    for idx, row in filtered_gdf.iterrows():
        # 获取几何中心点
        centroid = row['geometry'].centroid
        plt.text(centroid.x, centroid.y, row[name_field], 
                 fontsize=8, ha='center', va='center')
    
    # 设置标题和轴标签
    plt.title('指定省份地理位置和边界', fontsize=16)
    plt.xlabel('经度', fontsize=12)
    plt.ylabel('纬度', fontsize=12)
    
    # 添加网格线
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # 保存图像
    plt.savefig(output_path, dpi=dpi, bbox_inches='tight')
    print(f"地图已保存到: {output_path}")
    
    # 关闭图形，释放内存
    plt.close()
    
    return output_path


def generate_html_report(result_df: pd.DataFrame, map_path: str, output_path: str) -> str:
    """
    生成包含省份边界数据和地图的HTML报告
    
    参数:
        result_df: 包含省份边界数据的DataFrame
        map_path: 地图图像文件路径
        output_path: 输出HTML文件路径
        
    返回:
        保存的HTML文件路径
    """
    html_content = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>省份经纬度范围报告</title>
        <style>
            body {{ font-family: Arial, sans-serif; margin: 20px; }}
            h1 {{ color: #2c3e50; }}
            table {{ border-collapse: collapse; width: 100%; margin-top: 20px; }}
            th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
            th {{ background-color: #f2f2f2; }}
            tr:nth-child(even) {{ background-color: #f9f9f9; }}
            .map-container {{ margin-top: 30px; text-align: center; }}
            img {{ max-width: 100%; border: 1px solid #ddd; }}
        </style>
    </head>
    <body>
        <h1>省份经纬度范围报告</h1>
        
        <h2>经纬度边界数据</h2>
        <table>
            <tr>
                <th>省份</th>
                <th>全称</th>
                <th>最小经度</th>
                <th>最小纬度</th>
                <th>最大经度</th>
                <th>最大纬度</th>
                <th>经度范围</th>
                <th>纬度范围</th>
            </tr>
    """
    
    # 添加表格行
    for idx, row in result_df.iterrows():
        html_content += f"""
            <tr>
                <td>{row['省份']}</td>
                <td>{row['全称']}</td>
                <td>{row['最小经度']:.6f}</td>
                <td>{row['最小纬度']:.6f}</td>
                <td>{row['最大经度']:.6f}</td>
                <td>{row['最大纬度']:.6f}</td>
                <td>{row['经度范围']}</td>
                <td>{row['纬度范围']}</td>
            </tr>
        """
    
    # 添加地图和结束标签
    html_content += f"""
        </table>
        
        <div class="map-container">
            <h2>省份地理位置地图</h2>
            <img src="{os.path.basename(map_path)}" alt="省份地图">
        </div>
    </body>
    </html>
    """
    
    # 保存HTML文件
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(html_content)
    
    print(f"HTML报告已保存到: {output_path}")
    
    return output_path


def process_province_data(shp_path: str, target_provinces: List[str], 
                         output_dir: str = None, 
                         csv_filename: str = 'province_bounds_detailed.csv',
                         map_filename: str = 'province_map.png',
                         html_filename: str = 'province_report.html') -> Dict[str, str]:
    """
    处理省份数据的主函数，包括读取shapefile、提取边界、创建地图和生成报告
    
    参数:
        shp_path: shapefile文件路径
        target_provinces: 目标省份名称列表
        output_dir: 输出目录，默认为None（使用当前目录）
        csv_filename: CSV文件名，默认为'province_bounds_detailed.csv'
        map_filename: 地图文件名，默认为'province_map.png'
        html_filename: HTML报告文件名，默认为'province_report.html'
        
    返回:
        包含输出文件路径的字典
    """
    # 设置输出目录
    if output_dir is None:
        output_dir = os.path.dirname(shp_path)
    
    # 确保输出目录存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 设置输出文件路径
    csv_path = os.path.join(output_dir, csv_filename)
    map_path = os.path.join(output_dir, map_filename)
    html_path = os.path.join(output_dir, html_filename)
    
    try:
        # 读取shapefile
        gdf = read_province_shapefile(shp_path)
        
        # 筛选目标省份
        filtered_gdf = filter_provinces(gdf, target_provinces)
        
        # 提取边界数据
        result_df = extract_province_bounds(filtered_gdf)
        
        # 保存CSV文件
        result_df.to_csv(csv_path, index=False, encoding='utf-8-sig')
        print(f"省份边界数据已保存到: {csv_path}")
        
        # 打印结果
        print("\n省份经纬度范围:")
        for idx, row in result_df.iterrows():
            print(f"{row['省份']} ({row['全称']}): 经度 {row['经度范围']}, 纬度 {row['纬度范围']}")
        
        # 创建地图
        create_province_map(gdf, filtered_gdf, map_path)
        
        # 生成HTML报告
        generate_html_report(result_df, map_path, html_path)
        
        print("\n处理完成!")
        
        return {
            'csv_path': csv_path,
            'map_path': map_path,
            'html_path': html_path
        }
        
    except Exception as e:
        print(f"处理数据时出错: {e}")
        raise